[十二省联考2019]异或粽子

2020-02-20
十二省联考

题意

求序列$\{a_i\}$中连续异或和的前k大的和

题解

前缀和,每次在堆里找最大的分裂

用可持久化Trie维护

调试记录

Trie边界没弄好,写挂了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdio>
#include <queue>
#define LL long long
const int maxn = 5e5 + 5;
using namespace std;
struct T{
struct A{
int son[2], v, tim;
A(){
tim = -1;
v = 0;
}
}a[maxn * 50];
int tot = 0;
void insert(int u, int v, LL x, int dep, int tim){
a[v] = a[u]; a[v].v++;
if (dep < 0){ a[v].tim = tim; return; }
int d = (x >> (1ll * dep)) & 1ll;
insert(a[u].son[d], a[v].son[d] = ++tot, x, dep - 1, tim);
}
int find(int u, int v, int dep, LL x){
if (dep < 0) return a[v].tim;
int d = (x >> (1ll * dep)) & 1ll;
if (a[a[v].son[d ^ 1]].v - a[a[u].son[d ^ 1]].v != 0) return find(a[u].son[d ^ 1], a[v].son[d ^ 1], dep - 1, x);
return find(a[u].son[d], a[v].son[d], dep - 1, x);
}
}t; int rt[maxn];
int n, k; LL a[maxn];
struct A{
int s, l, r, pos;
bool operator<(A x)const{
return (a[s] ^ a[pos]) < (a[x.s] ^ a[x.pos]);
}
}; priority_queue <A> q;
signed main(){
// freopen("17.in", "r", stdin);
scanf("%d%d", &n, &k); t.insert(0, rt[0] = ++t.tot, 0, 32, 0);
for (int i = 1; i <= n; i++){
scanf("%lld", a + i); a[i] ^= a[i - 1];
t.insert(rt[i - 1], rt[i] = ++t.tot, a[i], 32, i);
} LL res = 0;
for (int i = 1; i <= n; i++)
q.push(A{i - 1, i, n, t.find(rt[i - 1], rt[n], 32, a[i - 1])});
while (k--){
A now = q.top(); q.pop();
res += (a[now.s] ^ a[now.pos]);
if (now.l < now.pos) q.push(A{now.s, now.l, now.pos - 1, t.find(rt[now.l - 1], rt[now.pos - 1], 32, a[now.s])});
if (now.pos < now.r) q.push(A{now.s, now.pos + 1, now.r, t.find(rt[now.pos], rt[now.r], 32, a[now.s])});
} printf("%lld\n", res);
return 0;
}